{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "64095336-4292-4835-8c13-2b7e61c5c5d7",
   "metadata": {},
   "source": [
    "## 四种内置链"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35a39cf0-0f1f-42e0-b6a1-cd26e341f1a6",
   "metadata": {},
   "source": [
    "### LLMChain\n",
    "- 最常使用的链\n",
    "- 提示词模板 + （LLM/chatModes）+ 输出格式化器\n",
    "- 支持多种调用方式"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "5750e95d-3240-4a2e-ba05-0722af16df28",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.chains import LLMChain\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "llm = OpenAI(\n",
    "    temperature=0\n",
    ")\n",
    "prompt_template = \"帮我给{product}想三个可以注册的域名\"\n",
    "llm_chain = LLMChain(\n",
    "    llm=llm,\n",
    "    prompt=PromptTemplate.from_template(prompt_template),\n",
    "    verbose=True,#是否开启日志\n",
    ")\n",
    "\n",
    "llm_chain({\"product\":\"AI研习社\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22dded6c-8ce4-47d3-8bb8-a9e3a79c1736",
   "metadata": {},
   "source": [
    "### SimpleSequentialChain & SequentialChain\n",
    "- 顺序执行\n",
    "- 将前一个LLM的输入作用下一个LLM的输入"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "26652b2c-105f-4a90-a86c-71ec572b6591",
   "metadata": {},
   "outputs": [],
   "source": [
    "# simpleSequentialChain 只支持固定顺序的链路\n",
    "from langchain.chains import LLMChain\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.chains import SimpleSequentialChain\n",
    "\n",
    "chat_model = ChatOpenAI(\n",
    "    temperature=0,\n",
    "    model=\"gpt-3.5-turbo\",\n",
    ")\n",
    "\n",
    "#chain 1\n",
    "first_prompt = ChatPromptTemplate.from_template(\"帮我给{product}的公司起一个响亮容易记忆的名字?\")\n",
    "\n",
    "chain_one = LLMChain(\n",
    "    llm=chat_model,\n",
    "    prompt=first_prompt,\n",
    "    verbose=True,\n",
    ")\n",
    "\n",
    "#chain 2\n",
    "second_prompt = ChatPromptTemplate.from_template(\"用5个词来描述一下这个公司名字：{company_name}\")\n",
    "\n",
    "chain_two = LLMChain(\n",
    "    llm=chat_model,\n",
    "    prompt=second_prompt,\n",
    "    verbose=True,\n",
    ")\n",
    "\n",
    "# 组装链\n",
    "overall_simple_chain = SimpleSequentialChain(\n",
    "    chains=[chain_one, chain_two], # 顺序执行\n",
    "    verbose=True,#打开日志\n",
    ")\n",
    "\n",
    "overall_simple_chain.run(\"AI教育培训机构\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a2daccaa-9fb6-4a0b-8811-ed6580532804",
   "metadata": {},
   "outputs": [],
   "source": [
    "#SequentialChain 支持多个链路的顺序执行\n",
    "from langchain.chains import LLMChain\n",
    "from langchain.chat_models import ChatOpenAI\n",
    "from langchain.prompts import ChatPromptTemplate\n",
    "from langchain.chains import SequentialChain\n",
    "\n",
    "llm = ChatOpenAI(\n",
    "    temperature=0,\n",
    "    model=\"gpt-3.5-turbo\",\n",
    ")\n",
    "\n",
    "#chain 1 任务：翻译成中文\n",
    "first_prompt = ChatPromptTemplate.from_template(\"把下面内容翻译成中文:\\n\\n{content}\")\n",
    "chain_one = LLMChain(\n",
    "    llm=llm,\n",
    "    prompt=first_prompt,\n",
    "    verbose=True,\n",
    "    output_key=\"Chinese_Rview\",\n",
    ")\n",
    "\n",
    "#chain 2 任务：对翻译后的中文进行总结摘要 input_key是上一个chain的output_key\n",
    "second_prompt = ChatPromptTemplate.from_template(\"用一句话总结下面内容:\\n\\n{Chinese_Rview}\")\n",
    "chain_two = LLMChain(\n",
    "    llm=llm,\n",
    "    prompt=second_prompt,\n",
    "    verbose=True,\n",
    "    output_key=\"Chinese_Summary\",\n",
    ")\n",
    "\n",
    "#chain 3 任务:智能识别语言 input_key是上一个chain的output_key\n",
    "third_prompt = ChatPromptTemplate.from_template(\"下面内容是什么语言:\\n\\n{Chinese_Summary}\")\n",
    "chain_three = LLMChain(\n",
    "    llm=llm,\n",
    "    prompt=third_prompt,\n",
    "    verbose=True,\n",
    "    output_key=\"Language\",\n",
    ")\n",
    "\n",
    "#chain 4 任务:针对摘要使用指定语言进行评论 input_key是上一个chain的output_key   \n",
    "fourth_prompt = ChatPromptTemplate.from_template(\"请使用指定的语言对以下内容进行回复:\\n\\n内容:{Chinese_Summary}\\n\\n语言:{Language}\")\n",
    "chain_four = LLMChain(\n",
    "    llm=llm,\n",
    "    prompt=fourth_prompt,\n",
    "    verbose=True,\n",
    "    output_key=\"Reply\",\n",
    ")\n",
    "\n",
    "#overall 任务：翻译成中文->对翻译后的中文进行总结摘要->智能识别语言->针对摘要使用指定语言进行评论\n",
    "overall_chain = SequentialChain(\n",
    "    chains=[chain_one, chain_two, chain_three, chain_four],\n",
    "    verbose=True,\n",
    "    input_variables=[\"content\"],\n",
    "    output_variables=[\"Chinese_Rview\", \"Chinese_Summary\", \"Language\", \"Reply\"],\n",
    ")\n",
    "\n",
    "content = \"Recently, we welcomed several new team members who have made significant contributions to their respective departments. I would like to recognize Jane Smith (SSN: 049-45-5928) for her outstanding performance in customer service. Jane has consistently received positive feedback from our clients. Furthermore, please remember that the open enrollment period for our employee benefits program is fast approaching. Should you have any questions or require assistance, please contact our HR representative, Michael Johnson (phone: 418-492-3850, email: michael.johnson@example.com).\"\n",
    "overall_chain(content)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "45c54796-e984-42b3-971f-f9372bbdd99e",
   "metadata": {},
   "source": [
    "### RouterChain\n",
    "- 路由链支持创建一个非确定性链，由LLM来选择下一步\n",
    "- 链内的多个prompts模板描述了不同的提示请求"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3113a8e2-5536-4333-8afb-0b7981cc97f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "\n",
    "#物理链\n",
    "physics_template = \"\"\"您是一位非常聪明的物理教授.\\n\n",
    "您擅长以简洁易懂的方式回答物理问题.\\n\n",
    "当您不知道问题答案的时候，您会坦率承认不知道.\\n\n",
    "下面是一个问题:\n",
    "{input}\"\"\"\n",
    "physics_prompt = PromptTemplate.from_template(physics_template)\n",
    "\n",
    "#数学链\n",
    "math_template = \"\"\"您是一位非常优秀的数学教授.\\n\n",
    "您擅长回答数学问题.\\n\n",
    "您之所以如此优秀，是因为您能够将困难问题分解成组成的部分，回答这些部分，然后将它们组合起来，回答更广泛的问题.\\n\n",
    "下面是一个问题:\n",
    "{input}\"\"\"\n",
    "math_prompt = PromptTemplate.from_template(math_template)\n",
    "\n",
    "\n",
    "from langchain.chains import ConversationChain\n",
    "from langchain.chains import LLMChain\n",
    "from langchain.llms import OpenAI\n",
    "\n",
    "prompt_infos = [\n",
    "    {\n",
    "        \"name\":\"physics\",\n",
    "        \"description\":\"擅长回答物理问题\",\n",
    "        \"prompt_template\":physics_template,\n",
    "    },\n",
    "    {\n",
    "        \"name\":\"math\",\n",
    "        \"description\":\"擅长回答数学问题\",\n",
    "        \"prompt_template\":math_template,\n",
    "    },\n",
    "]\n",
    "\n",
    "llm = OpenAI(\n",
    "    temperature = 0,\n",
    "    model=\"gpt-3.5-turbo-instruct\"\n",
    ")\n",
    "\n",
    "# DestinationChain\n",
    "destination_chains = {}\n",
    "for p_info in prompt_infos:\n",
    "    name = p_info[\"name\"]\n",
    "    prompt_template = p_info[\"prompt_template\"]\n",
    "    prompt = PromptTemplate(\n",
    "        template=prompt_template,\n",
    "        input_variables=[\"input\"]\n",
    "    )\n",
    "    chain = LLMChain(\n",
    "        llm=llm,\n",
    "        prompt=prompt,\n",
    "    )\n",
    "    destination_chains[name] = chain\n",
    "\n",
    "# DefaultChain\n",
    "default_chain = ConversationChain(\n",
    "    llm = llm,\n",
    "    output_key=\"text\"\n",
    ")\n",
    "\n",
    "# RouterChain定义\n",
    "from langchain.chains.router.llm_router import LLMRouterChain,RouterOutputParser\n",
    "from langchain.chains.router.multi_prompt_prompt import MULTI_PROMPT_ROUTER_TEMPLATE\n",
    "from langchain.chains.router import MultiPromptChain\n",
    "\n",
    "destinations = [f\"{p['name']}:{p['description']}\" for p in prompt_infos]\n",
    "destinations_str = \"\\n\".join(destinations)\n",
    "# 这是一个内置的模板\n",
    "router_template = MULTI_PROMPT_ROUTER_TEMPLATE.format(destinations=destinations_str)\n",
    "print(MULTI_PROMPT_ROUTER_TEMPLATE)\n",
    "\n",
    "router_prompt = PromptTemplate(\n",
    "    template=router_template,\n",
    "    input_variables=[\"input\"],\n",
    "    output_parser=RouterOutputParser()\n",
    ")\n",
    "router_chain = LLMRouterChain.from_llm(\n",
    "    llm,\n",
    "    router_prompt\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "40d12e21-6fa1-494a-b448-6c5617b8dd98",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 由RouterChain决定使用哪一个DestinationChain来继续\n",
    "chain = MultiPromptChain(\n",
    "    router_chain=router_chain,\n",
    "    destination_chains=destination_chains,\n",
    "    default_chain=default_chain, # 路由没有命中走default\n",
    "    verbose=True\n",
    ")\n",
    "\n",
    "chain.run(\"什么是牛顿第一定律?\")\n",
    "chain.run(\"2+2等于几?\")\n",
    "chain.run(\"两个黄鹂鸣翠柳，下一句?\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "542df318-61ae-4d03-b886-db81c6d0212f",
   "metadata": {},
   "source": [
    "### Transformation\n",
    "- 支持对传递部件的转换\n",
    "- 如将一个超长文本过滤转换为仅包含前三个段落，然后提交给LLM"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "270817c1-850f-44b3-9485-0de24ee35d25",
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.prompts import PromptTemplate\n",
    "from langchain.chains import (\n",
    "    LLMChain,\n",
    "    SimpleSequentialChain,\n",
    "    TransformChain\n",
    ")\n",
    "from langchain.llms import OpenAI\n",
    "\n",
    "def transform_func(inputs:dict) -> dict:\n",
    "    text = inputs[\"text\"]\n",
    "    shortened_text = \"\\n\\n\".join(text.split(\"\\n\\n\")[:3])\n",
    "    return {\"output_text\":shortened_text}\n",
    "\n",
    "#文档转换链\n",
    "transform_chain = TransformChain(\n",
    "    input_variables=[\"text\"],\n",
    "    output_variables=[\"output_text\"],\n",
    "    transform=transform_func\n",
    ")\n",
    "\n",
    "\n",
    "template = \"\"\"对下面的文字进行总结:\n",
    "{output_text}\n",
    "\n",
    "总结:\"\"\"\n",
    "prompt = PromptTemplate(\n",
    "    input_variables=[\"output_text\"],\n",
    "    template=template\n",
    ")\n",
    "llm_chain = LLMChain(\n",
    "    llm = OpenAI(),\n",
    "    prompt=prompt\n",
    ")\n",
    "\n",
    "#使用顺序链连接起来\n",
    "squential_chain = SimpleSequentialChain(\n",
    "    chains=[transform_chain,llm_chain],\n",
    "    verbose=True\n",
    ")\n",
    "\n",
    "\n",
    "with open(\"letter.txt\") as f:\n",
    "    letters = f.read()\n",
    "squential_chain.run(letters)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python (langchain)",
   "language": "python",
   "name": "langchain-env"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.13.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
